package com.czl.common.util;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.*;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 工具类
 */
public class Tools {

    public static String logString(String... str) {
        StringBuffer sbs = new StringBuffer();
        if (str != null && str.length > 0) {
            for (String s : str) {
                sbs.append("|");
                sbs.append(s);
            }
        }
        if (sbs.length() > 1) {
            return sbs.substring(1);
        }
        return sbs.toString();
    }

    public static String logString(Object... str) {
        StringBuffer sbs = new StringBuffer();
        if (str != null && str.length > 0) {
            for (Object s : str) {
                sbs.append("|");
                sbs.append(toString(s));
            }
        }
        if (sbs.length() > 1) {
            return sbs.substring(1);
        }
        return sbs.toString();
    }

    /**
     * 将对象转换成long值
     *
     * @param str
     * @return
     */
    public final static long toLong(Object str) {
        return toLong(str, -1);
    }

    /**
     * 将对象转换成long值
     *
     * @param str
     * @param defaultValue 当对象为空时的缺省值
     * @return
     */
    public final static long toLong(Object str, long defaultValue) {
        if (str != null) {
            try {
                Class<?> cType = str.getClass();
                if (cType == Double.class || cType == double.class)
                    return ((Double) str).longValue();
                else if (cType == Float.class || cType == float.class)
                    return ((Float) str).longValue();
                else if (cType == Long.class || cType == long.class)
                    return ((Long) str).longValue();
                else if (cType == Integer.class || cType == int.class)
                    return ((Integer) str).longValue();
                else if (cType == Character.class || cType == char.class)
                    return (long) ((Character) str).charValue();
                else if (cType == Byte.class || cType == byte.class)
                    return ((Byte) str).longValue();
                else if (str instanceof Date)
                    return ((Date) str).getTime();
                return Long.parseLong(str.toString());
            } catch (Exception e) {

            }
        }
        return defaultValue;
    }

    /**
     * 将对象转换成String
     *
     * @param str
     * @return
     */
    public final static String toString(Object str) {
        return toString(str, null);
    }

    /**
     * 将对象转换成String
     *
     * @param str
     * @param defaultValue 当对象为空时的缺省值
     * @return
     */
    public final static String toString(Object str, String defaultValue) {
        if (str != null) {
            if (str instanceof String)
                return (String) str;
            else {
                try {
                    return str.toString();
                } catch (Exception e) {

                }
            }
        }
        return defaultValue;
    }

    /**
     * 将对象转换成int值
     *
     * @param str
     * @return
     */
    public final static int toInt(Object str) {
        return toInt(str, -1);
    }

    /**
     * @param str
     * @param defaultValue 当对象为空时的缺省值
     * @return
     */
    public final static int toInt(Object str, int defaultValue) {
        if (str != null) {
            try {
                Class<?> cType = str.getClass();
                if (cType == Double.class || cType == double.class)
                    return ((Double) str).intValue();
                else if (cType == Float.class || cType == float.class)
                    return ((Float) str).intValue();
                else if (cType == Long.class || cType == long.class)
                    return ((Long) str).intValue();
                else if (cType == Integer.class || cType == int.class)
                    return ((Integer) str).intValue();
                else if (cType == Character.class || cType == char.class)
                    return (int) ((Character) str).charValue();
                else if (cType == Byte.class || cType == byte.class)
                    return ((Byte) str).intValue();
                return Integer.parseInt(str.toString());
            } catch (Exception e) {

            }
        }
        return defaultValue;
    }

    /**
     * 将对象转换成double值
     *
     * @param str
     * @return
     */
    public final static double toDouble(Object str) {
        return toDouble(str, -1);
    }

    /**
     * 将对象转换成double值
     *
     * @param str
     * @param defaultValue 当对象为空时的缺省值
     * @return
     */
    public final static double toDouble(Object str, double defaultValue) {
        if (str != null) {
            try {
                Class<?> cType = str.getClass();
                if (cType == Double.class || cType == double.class)
                    return ((Double) str).doubleValue();
                else if (cType == Float.class || cType == float.class)
                    return ((Float) str).doubleValue();
                else if (cType == Long.class || cType == long.class)
                    return ((Long) str).doubleValue();
                else if (cType == Integer.class || cType == int.class)
                    return ((Integer) str).doubleValue();
                else if (cType == Character.class || cType == char.class)
                    return (double) ((Character) str).charValue();
                else if (cType == Byte.class || cType == byte.class)
                    return ((Byte) str).doubleValue();
                else if (str instanceof Date)
                    return (double) ((Date) str).getTime();
                return Double.parseDouble(str.toString());
            } catch (Exception e) {

            }
        }
        return defaultValue;
    }

    /**
     * 将对象转换成float值
     *
     * @param str
     * @return
     */
    public final static float toFloat(Object str) {
        return toFloat(str, -1);
    }

    /**
     * 将对象转换成float值
     *
     * @param str
     * @param defaultValue 当对象为空时的缺省值
     * @return
     */
    public final static float toFloat(Object str, float defaultValue) {
        if (str != null) {
            try {
                Class<?> cType = str.getClass();
                if (cType == Double.class || cType == double.class)
                    return ((Double) str).floatValue();
                else if (cType == Float.class || cType == float.class)
                    return ((Float) str).floatValue();
                else if (cType == Long.class || cType == long.class)
                    return ((Long) str).floatValue();
                else if (cType == Integer.class || cType == int.class)
                    return ((Integer) str).floatValue();
                else if (cType == Character.class || cType == char.class)
                    return (float) ((Character) str).charValue();
                else if (cType == Byte.class || cType == byte.class)
                    return ((Byte) str).floatValue();
                return Float.parseFloat(str.toString());
            } catch (Exception e) {

            }
        }
        return defaultValue;
    }

    /**
     * 判断字符串是否不为空且长度大于零
     *
     * @param str
     * @return
     */
    public final static boolean stringIsNotNull(String str) {
        return str != null && !"".equals(str.toString().trim()) && !"null".equalsIgnoreCase(str);
    }

    /**
     * 判断字符串们是否不为空且长度大于零
     *
     * @param str string列表
     * @return
     */
    public final static boolean stringIsNotNull(String... str) {
        boolean ok = false;
        if (str != null) {
            for (String s : str) {
                if (!stringIsNotNull(s))
                    return false;
                else
                    ok = true;
            }
        }
        return ok;
    }

    public static String JVM() {
        return System.getProperty("instanceKey", "jvm");
    }
    public final static boolean toBoolean(Object str) {
        return toBoolean(str, false);
    }
    public final static boolean toBoolean(Object str, boolean defaultValue) {
        boolean ok = defaultValue;
        if (str != null){
            if (str instanceof Boolean)
                return ((Boolean) str).booleanValue();
            str = str.toString().toLowerCase().trim();
            if ("true".equals(str))
                ok = true;
            else if ("false".equals(str))
                ok = false;
            else if ("ok".equals(str))
                ok = true;
            else if ("on".equals(str))
                ok = true;
            else if ("yes".equals(str))
                ok = true;
            else if ("no".equals(str))
                ok = false;
            else if ("off".equals(str))
                ok = false;
            else if ("not".equals(str))
                ok = false;
            {
                int n = toInt(str);
                if (n == 0)
                    ok = false;
                else if (n > 0)
                    ok = true;
            }
        }

        return ok;
    }
    /**
     * byte数组转化为long数组
     *
     * @param byteArray
     * @return
     */
    public final static long[] byteArrayToLongArray(byte[] byteArray) {
        if (byteArray == null || byteArray.length < 8)
            return null;
        long[] longArray = new long[byteArray.length / 8];
        for (int i = 0; i < longArray.length; i++) {
            longArray[i] = (((long) byteArray[0 + 8 * i] & 0xff) << 56) | (((long) byteArray[1 + 8 * i] & 0xff) << 48)
                    | (((long) byteArray[2 + 8 * i] & 0xff) << 40) | (((long) byteArray[3 + 8 * i] & 0xff) << 32)
                    | (((long) byteArray[4 + 8 * i] & 0xff) << 24) | (((long) byteArray[5 + 8 * i] & 0xff) << 16)
                    | (((long) byteArray[6 + 8 * i] & 0xff) << 8) | (((long) byteArray[7 + 8 * i] & 0xff) << 0);
        }
        return longArray;
    }

    private final static ObjectMapper SerializationMapper = getSerializationMapper();

    private static ObjectMapper getSerializationMapper() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        // mapper.configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false);
        return mapper;
    }

    public final static String objectToJsonString(Object o) {
        if (o != null) {
            try {
                return SerializationMapper.writeValueAsString(o);
            } catch (Exception e) {
//                ToolsLogger.systemLog.error(Tools.logString(e, JVM(), "objectToJsonString error", o));
            }
        }
        return null;
    }

    /**
     * 把url中的参数值进行编码
     * 
     * @param par
     * @return
     */
    public final static String encodePar(String par) {
        return encodePar(par, null);
    }

    /**
     * 把url中的参数值进行编码
     * 
     * @param par
     * @return
     */
    public final static String encodePar(String par, String encode) {
        if (par != null && !par.equals("")) {
            if (!stringIsNotNull(encode))
                encode = "UTF-8";
            try {
                par = java.net.URLEncoder.encode(par, encode);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
        return par;
    }

    /**
     * 以安全的方式sleep
     * 
     * @param time
     */
    public final static void sleep(long time) {
        try {
            Thread.sleep(time);
            Thread.yield();
        } catch (Exception e) {
        }
    }

    /**
     * 将字符串中的某些字符串去掉
     * 
     * @param str
     * @param key
     * @return
     */
    public final static String removeAll(String str, String key) {
        return replaceAll(str, key, null);
    }

    /**
     * 将字符串中某些字符串替换成其他字符串
     * 
     * @param str
     * @param key
     * @param to
     * @return
     */
    public final static String replaceAll(String str, String key, String to) {
        if (str != null && key != null && !str.equals("") && !key.equals("")) {
            StringBuffer strbuf = new StringBuffer();
            int begin = 0, slen = str.length();
            for (int npos = 0, klen = key.length(); begin < slen
                    && (npos = str.indexOf(key, begin)) >= begin; begin = npos + klen) {
                strbuf.append(str.substring(begin, npos));
                if (to != null)
                    strbuf.append(to);
            }
            if (begin == 0)
                return str;
            if (begin < slen)
                strbuf.append(str.substring(begin));
            return strbuf.toString();
        }
        return str;
    }

    /**
     * 将json字符串转换成对象
     * 
     * @param jsonString
     * @return
     */
    public final static Object jsonStringToObject(String jsonString) {
        return jsonStringToObject(jsonString, Object.class);
    }

    private final static ObjectMapper DeserializationMapper = getDeserializationMapper();

    private static ObjectMapper getDeserializationMapper() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        return mapper;
    }

    public final static <T> T jsonStringToObject(String jsonString, Class<T> valueType) {
        if (jsonString != null) {
            jsonString = jsonString.trim();
            if (!"".equals(jsonString)) {
                try {
                    return DeserializationMapper.readValue(jsonString, valueType);
                } catch (Exception e) {
//                    ToolsLogger.systemLog.error(Tools.logString(e, "jsonToObject", JVM(), jsonString));
                }
            }
        }
        return null;
    }

    public static long verToLong(String ver, int digit) {
        long n = 0L;
        if (digit < 1) {
            digit = 1;
        }

        if (ver != null) {
            long wei = 1L;
            String[] sl = ver.trim().split("\\.");

            for (int i = digit - 1; i >= 0; --i) {
                if (i < sl.length) {
                    n += wei * toLong(sl[i], 0L);
                }

                wei *= 1000L;
            }
        }

        return n;
    }

    public static <T> Map<String, Object> beanToMap(T bean) {
        return beanToMap(bean, null, null);
    }

    public static <T> Map<String, Object> beanToMap(T bean, T stopBean, String enumMethod) {
        if (bean == null) {
            return null;
        }
        Map<String, Object> res = new HashMap<String, Object>();
        try {
            BeanInfo beanInfo;
            if (stopBean == null) {
                beanInfo = Introspector.getBeanInfo(bean.getClass());
            } else {
                beanInfo = Introspector.getBeanInfo(bean.getClass(), stopBean.getClass());
            }
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor prop : propertyDescriptors) {
                String key = prop.getName();
                if (!key.equals("class")) {
                    Method method = prop.getReadMethod();
                    Object value = method.invoke(bean);
                    if (Tools.stringIsNotNull(enumMethod)) {
                        if (prop.getPropertyType().isEnum()) {
                            T[] aa = (T[]) value.getClass().getEnumConstants();
                            for (T t : aa) {
                                if (Tools.toString(value).equalsIgnoreCase(Tools.toString(t))) {
                                    value = getMethodValue(t, enumMethod, null);
                                    break;
                                }
                            }
                        }
                    }
                    if (value == null) {
                        switch (prop.getPropertyType().getSimpleName()) {
                        case "String":
                            value = "";
                            break;
                        case "Long":
                            value = -1l;
                            break;
                        case "Integer":
                            value = -1;
                            break;
                        }
                    }
                    res.put(key, value);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return res;
    }

    public static <T> T mapToBean(Map<String, Object> map, Class<T> clazz) {
        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(clazz);
            T obj = clazz.newInstance();

            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (int i = 0; i < propertyDescriptors.length; i++) {
                PropertyDescriptor descriptor = propertyDescriptors[i];
                String propertyName = descriptor.getName();
                if (map.containsKey(propertyName)) {
                    try {
                        Object value = map.get(propertyName);
                        if (value != null) {
                            descriptor.getWriteMethod().invoke(obj, value);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
            return obj;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private static <T> Object getMethodValue(T t, String methodName, Object... args) {
        Object result = "";
        Method[] methods = t.getClass().getMethods();
        if (methods.length <= 0)
            return result;
        Method targetMethod = null;
        for (Method met : methods) {
            if (met.getName().equalsIgnoreCase(methodName)) {
                targetMethod = met;
                break;
            }
        }
        if (targetMethod == null)
            return result;
        try {
            result = targetMethod.invoke(t, args);
        } catch (Exception e) {
//            ToolsLogger.systemLog.error("com.jiayuan.java2.tools.util.getMethodValue_Error", e);
        }
        return result == null ? "" : result;
    }

    /**
     * 将指定对象翻译成指定class类型，方法2
     * 
     * @param <T>
     * @param o
     * @param valueType
     * @return
     */
    public final static <T> T translateObjectValueType2(Object o, Class<T> valueType) {
        if (o != null && valueType != null) {
            if (valueType == Object.class)
                return (T) o;
            try {
                Constructor<T> constructor = valueType.getConstructor(o.getClass());
                return constructor.newInstance(o);
            } catch (Exception e) {
            }
        }
        return null;
    }

    /**
     * 将指定对象翻译成指定class类型
     * 
     * @param <T>
     * @param o
     * @param valueType
     * @return
     */
    @SuppressWarnings("unchecked")
    public final static <T> T translateObjectValueType(Object o, Class<T> valueType) {
        if (o != null && valueType != null) {
            if (valueType.isInstance(o))
                return (T) o;
        }
        return null;
    }

    /**
     * 获取对象中的信息，弱化对象类型，可深入读取 可支持的对象，Object，List，Map，Array
     * 
     * @param o
     * @param keys
     * @return
     */
    public final static Object getObjectByKeys(Object o, String... keys) {
        if (keys != null && keys.length > 0 && o != null) {
            Object obj = o;
            for (String k : keys) {
                if (stringIsNotNull(k)) {
                    obj = getObjectByKey(obj, k);
                    if (obj == null)
                        break;
                } else
                    return null;
            }
            return obj;
        }
        return null;
    }

    /**
     * 获取对象中的信息，弱化对象类型，可深入读取 可支持的对象，Object，List，Map，Array
     * 
     * @param <T>
     * @param o
     * @param key
     * @param valueType
     * @return
     */
    public final static <T> T getObjectByKey(Object o, String key, Class<T> valueType) {
        Object oo = getObjectByKey(o, key);
        if (oo != null) {
            return translateObjectValueType(oo, valueType);
        }
        return null;
    }

    /**
     * 获取对象中的信息，弱化对象类型 可支持的对象，Object，List，Map，Array
     * 
     * @param o
     * @param key
     * @return
     */
    public final static Object getObjectByKey(Object o, String key) {
        if (o != null && stringIsNotNull(key)) {
            if (key.indexOf('.') >= 0) {
                String[] keys = key.split("\\.");
                if (keys != null && keys.length > 1) {
                    return getObjectByKeys(o, keys);
                }
            }
            if (o.getClass().isArray()) {
                int index = toInt(key, -1);
                if (index >= 0 && index < Array.getLength(o))
                    return Array.get(o, index);
                return null;
            } else if (o instanceof Map) {
                return ((Map) o).get(key);
            } else if (o instanceof List) {
                int index = toInt(key, -1);
                if (index >= 0 && index < ((List) o).size())
                    return ((List) o).get(index);
                return null;
            } else if (o instanceof Collection) {
                int index = toInt(key, -1);
                if (index >= 0 && index < ((Collection) o).size()) {
                    for (Object oo : ((Collection) o)) {
                        if (index == 0)
                            return oo;
                        index--;
                    }
                }
                return null;
            } else {
                try {
                    Class<?> c = o.getClass();
                    Field f = null;
                    while (f == null && c != null) {
                        try {
                            f = c.getDeclaredField(key);
                        } catch (Exception e) {
                        }
                        if (f != null)
                            break;
                        try {
                            c = c.getSuperclass();
                        } catch (Exception e) {
                        }
                    }
                    if (f != null) {
                        f.setAccessible(true);
                        return f.get(o);
                    }
                } catch (Exception e) {
                }
            }
        }
        return null;
    }

    private static final Map<String, Map<String, List<Method>>> classMethodCache = new HashMap<String, Map<String, List<Method>>>();

     /**
     * 获取指定类的指定方法对象
     * @param className
     * @param methodName
     * @param parameters
     * @return
     */
    public final static Method getClassMethod(String className, String methodName, Object[] parameters)
    {
    	return getClassMethod(className, methodName, parameters, true);
    }
    
    /**
     * 获取指定类的指定方法对象
     * @param className
     * @param methodName
     * @param parameters
     * @param caseParametersInstance	每一个参数类型是否都要匹配
     * @return
     */
    public final static Method getClassMethod(String className, String methodName, Object[] parameters, boolean caseParametersInstance)
    {
    	if(stringIsNotNull(className, methodName))
    	{
    		className = className.trim();
    		methodName = methodName.trim();
	    	Map<String, List<Method>> cm = classMethodCache.get(className);
	    	if(cm == null)
	    	{
	    		synchronized(classMethodCache)
	    		{
	    			cm = classMethodCache.get(className);
	    	    	if(cm == null)
	    	    	{
	    	    		cm = new HashMap<String, List<Method>>();
	    	    		classMethodCache.put(className, cm);
	    	    	}
	    		}
	    	}
	    	if(cm != null)
	    	{
	    		List<Method> lm = cm.get(methodName);
	    		if(lm == null)
	    		{
		    		synchronized(cm)
		    		{
		    			lm = cm.get(methodName);
		    	    	if(lm == null)
		    	    	{
		    	    		lm = new LinkedList<Method>();
		    	            try
		    	            {
		    	            	Class<?> c = Class.forName(className);
		    	            	while(c != null)
		    	            	{
			    					Method[] ml = c.getDeclaredMethods();
			    					if(ml != null && ml.length > 0)
			    					{
			    						for(Method m : ml)
			    						{
			    							if(m.getName().equals(methodName))
			    								lm.add(m);
			    						}
			    					}
		    	            		c = c.getSuperclass();
		    	            	}
		    	            } catch (Exception e)
		    	            {
		    	            }
		    	    		cm.put(methodName, lm);
		    	    	}
		    		}
	    		}
	    		if(lm != null)
	    		{
					Class<?>[] cl = null;
					Method runm = null;
					Method funm = null;
					int i = 0;
					boolean caseto = false;
					for(Method m : lm)
					{
						if(funm == null)
							funm = m;
						cl = m.getParameterTypes();
						if(cl != null && cl.length > 0)
						{
							if(parameters != null && parameters.length == cl.length)
							{
								caseto = true;
								if(caseParametersInstance)
								{
									for(i = 0;i < cl.length && caseto;i ++)
									{
										if(parameters[i] != null)
											caseto &= cl[i].isInstance(parameters[i]);
									}
								}
								if(caseto)
								{
									runm = m;
									break;
								}
							}
						}
						else if(parameters == null || parameters.length == 0)
						{
							runm = m;
							break;
						}
					}
					if(runm == null)
						runm = funm;
					if(runm != null)
					{
						return runm;
					}
	    		}
	    	}
    	}
    	return null;
    }
    
    /**
     * 运行指定的类的指定方法3
     * 
     * @param classObject
     * @param methodName
     * @param parameters
     * @return
     * @throws IllegalArgumentException
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     */
    public final static Object runClassMethod3(Object classObject, String methodName, Object[] parameters)
            throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
        if (classObject != null && stringIsNotNull(methodName)) {
            Method m = getClassMethod(classObject.getClass().getName(), methodName, parameters);
            if (m != null) {
                m.setAccessible(true);
                return m.invoke(classObject, parameters);
            }
        }
        return null;
    }

    public static String replaceBlank(String str) {
        String dest = "";
        if (str!=null) {
            Pattern p = Pattern.compile("\\s*|\t|\r|\n");
            Matcher m = p.matcher(str);
            dest = m.replaceAll("");
        }
        return dest;
    }
    public static void main(String[] args) {
        /*
         * ChatRoomRecord c = new ChatRoomRecord(); c.setNickname("czw"); Map<String,
         * Object> res = Tools.beanToMap(c, new BaseEntityEx());
         * System.out.println(Tools.objectToJsonString(res)); ChatRoomRecord b =
         * Tools.mapToBean(res,ChatRoomRecord.class);
         * System.out.println(b.getNickname());
         */
    }
    
    /**
     * @title 随机正整数函数
     * @param min
     * @param max
     * @author 邓毅
     * @email dengyi1@jiayuan.com
     * @date 2020年3月13日
     */
	public static int createRandom(int min, int max) {
		if (max < 0 || min < 0) {
			return -1;
		}
		if (min > max) {
			int tempI = max;
			max = min;
			min = tempI;
		}
		Random random = new Random();
		return random.nextInt(max - min + 1) + min;
	}

    /**
     * 将long型十进制数字转换成62进制字符串
     *
     * @param decNum
     * @param defaultValue
     *
     */
    public final static String longToN62(Long decNum, String defaultValue) {
        return (decNum != null) ? NumberConverter.decToN62(decNum) : defaultValue;
    }

    /**
     * 将62进制字符串数换成long型十进制数字
     *
     * @param n62Str
     * @param defaultValue
     *
     */
    public final static Long n62ToLong(String n62Str, Long defaultValue) {

        Long decNum = null;

        try {
            decNum = NumberConverter.n62ToDec(n62Str);
        } catch(IllegalArgumentException illegalArgumentException) {
            decNum = null;
        }

        return (decNum != null) ? decNum : defaultValue;
    }
}